package snapex.user.service.impl;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;

import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import snapex.core.SnapexApplicationException;
import snapex.core.ValidationFailureException;
import snapex.core.mapper.UserDynamicSqlSupport;
import snapex.core.mapper.UserGroupMemberDynamicSqlSupport;
import snapex.core.mapper.UserGroupMemberMapper;
import snapex.core.mapper.UserLogonCodeDynamicSqlSupport;
import snapex.core.mapper.UserLogonCodeMapper;
import snapex.core.mapper.UserOrganizationDynamicSqlSupport;
import snapex.core.mapper.UserOrganizationMapper;
import snapex.core.model.MyGrantedAuthority;
import snapex.core.model.User;
import snapex.core.model.UserGroupMember;
import snapex.core.model.UserLogonCode;
import snapex.core.model.UserOrganization;
import snapex.user.mapper.UserMapper;
import snapex.user.service.IUserService;

@Slf4j
@Service
public class UserService implements IUserService {

	@Autowired
	private UserMapper userMapper;
	
	@Autowired
	private UserOrganizationMapper userOrganizationMapper;
	
	@Autowired
	private UserGroupMemberMapper userGroupMemberMapper;
	
	@Autowired
	private UserLogonCodeMapper userLogonCodeMapper;
	
	@Override
	public User getByUsername(String username) throws UsernameNotFoundException {
		
		User user = userMapper.selectByUsername(username);
		if(user == null) {
			
			user = userMapper.selectByPrimaryKey(username);
			
			if(user == null) {
				throw new UsernameNotFoundException(username);
			}
		}
		
		List<MyGrantedAuthority> authorities = userMapper.selectAuthorityByUsername(user.getUsername());
		
		user.setAuthorities(authorities);
		
		return user;
	}
	
	@Override
	public User getByUserId(String userId) throws UsernameNotFoundException{
		User user = userMapper.selectByUserId(userId);
		if(user == null) {			
			throw new UsernameNotFoundException(userId);			
		}
		
		List<MyGrantedAuthority> authorities = userMapper.selectAuthorityByUsername(user.getUsername());
		
		user.setAuthorities(authorities);
		
		return user;
	}
	
	@Override
	public User getByHashKey(String hashKey) throws UsernameNotFoundException{
		
		List<User> users = userMapper.selectDistinctByExample().where(UserDynamicSqlSupport.wechatKey, isEqualTo(hashKey)).build().execute();
		if(users.isEmpty()) {
			throw new SnapexApplicationException("User not found: "+ hashKey);
		}
		
		User user = users.get(0);
		
		List<MyGrantedAuthority> authorities = userMapper.selectAuthorityByHashKey(hashKey);
		
		user.setAuthorities(authorities);
		
		return user;
	}
	
	@Override
	public byte[] getCodeByHashKey(String hashKey) throws SnapexApplicationException{
		
		UserLogonCode userLogonCode = userLogonCodeMapper.selectByPrimaryKey(hashKey);
		
		log.debug("*****userLogonCode:{}",userLogonCode);
		
		if(userLogonCode != null) {
			return userLogonCode.getData();
		}
		
		return null;
	}
	
	@Override
	public String saveCodeByHashKey(String hashKey, byte[] data) throws SnapexApplicationException{
		
		UserLogonCode code = new UserLogonCode();
		code.setHashKey(hashKey);
		code.setData(data);
		
		if(1 == userLogonCodeMapper.countByExample().where(UserLogonCodeDynamicSqlSupport.hashKey, isEqualTo(hashKey)).build().execute().intValue()) {
			userLogonCodeMapper.updateByPrimaryKey(code);
		}else {
			userLogonCodeMapper.insert(code);
		}
		return hashKey;
	}
	
	@Override
	public User getByOpenId(String openId) throws SnapexApplicationException{
		return userMapper.selectByOpenId(openId);		
	}
	
	@Override
	public String register(String hashUsername) throws SnapexApplicationException{
		
		log.debug("****register: hashUsername={}",hashUsername);
		
		User user = new User();		
		user.setUserId(hashUsername);		
		user.setLocked("N");
		user.setDisabled("N");
		user.setCredentialExpired("N");
		String wechatKey;
		User existingUser = userMapper.selectByPrimaryKey(hashUsername);
		if(existingUser == null) {
			log.debug("****register: create user hashUsername={}",hashUsername);
			user.setUsername(hashUsername);
			user.setPasscode(RandomStringUtils.randomNumeric(6));
			user.setPassword("{noop}" + RandomStringUtils.randomAlphanumeric(6));
			user.setCreateTimestamp(new Date(System.currentTimeMillis()));
			wechatKey = RandomStringUtils.randomAlphanumeric(30);
			user.setWechatKey(wechatKey);			
			userMapper.insertSelective(user);
			
			UserOrganization userOrg = new UserOrganization();
			userOrg.setOrgCode("HTC_SNAPEX");
			userOrg.setUserId(hashUsername);
			userOrganizationMapper.insert(userOrg);
			
			UserGroupMember member = new UserGroupMember();
			member.setUserGroupCode("UGRP_EMPLOYEE");
			member.setUserId(hashUsername);
			userGroupMemberMapper.insert(member);
		}
		else {
			log.debug("****register: update user hashUsername={}",hashUsername);
			userMapper.updateByPrimaryKeySelective(user);
			
			wechatKey = existingUser.getWechatKey();				
		}			
		
		log.debug("****register: hashUsername={}, wechatKey={}",hashUsername, wechatKey);
		
		return wechatKey;
	}
	
//	@Override
//	public String registerWechat(User user) throws SnapexApplicationException {
//
//		if(StringUtils.isEmpty(user.getUserId())){
//			throw new ValidationFailureException("userId is missing");
//		}
//	
//		if(StringUtils.isEmpty(user.getPasscode())){
//			throw new ValidationFailureException("passcode is missing");
//		}
//	
//		if(StringUtils.isEmpty(user.getPassword())){
//			//throw new ValidationFailureException("password is missing");
//			user.setPassword("{noop}" + user.getPasscode());
//		}
//		
//		user.setUsername(user.getUserId());
//		
//		//generate hashKey
//		String hashKey = DigestUtils.md5DigestAsHex(user.getUserId().getBytes()) +DigestUtils.md5DigestAsHex(user.getPasscode().getBytes());
//		
//		user.setHashKey(hashKey);
//		
//		User existingUser = userMapper.selectByPrimaryKey(user.getUserId());
//		if(existingUser == null) {		
//			user.setLocked("N");
//			user.setDisabled("N");
//			user.setCredentialExpired("N");
//			userMapper.insert(user);
//		}
//		else {
//			userMapper.updateByPrimaryKeySelective(user);			
//		}			
//		
//		return hashKey;
//	}
	
	public User registerWechatOpenId(String wechatKey, String openId) throws SnapexApplicationException{
		User user = new User();
		
		user.setWechatKey(wechatKey);
		user.setOpenId(openId);
		
		if(userMapper.updateByHashKeySelective(user) == 0) {
			log.error("*****Could not found wechatKey[{}] for openid[{}]",wechatKey, openId);
			throw new ValidationFailureException(String.format("wechatKey [%s] not found", wechatKey));
		}
				
		return user;
	}
	
	@Override
	public boolean logout(String username) {
				
		if(userMapper.deleteByPrimaryKey(username) == 0) {
			log.error("*****Could not logout for non-existing user[{}]", username);
			return false;
		}
		
		userOrganizationMapper.deleteByExample().where(UserOrganizationDynamicSqlSupport.userId, isEqualTo(username)).build().execute();
		userGroupMemberMapper.deleteByExample().where(UserGroupMemberDynamicSqlSupport.userId, isEqualTo(username)).build().execute();
		
		log.error("*****User [{}] logout", username);
		
		return true;
	}
}
